package com.example.utils;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.loyo.Result;
import com.gitee.loyo.config.ChargeProperties;
import com.gitee.loyo.err.RequestFailureException;
import com.gitee.loyo.utils.CryptoUtils;
import com.gitee.loyo.utils.OkHttpHelper;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.io.IOException;
import java.lang.reflect.Type;
import java.net.SocketTimeoutException;

@Slf4j
@Primary
@Component
public class CustomOkHttpHelper extends OkHttpHelper {

    public CustomOkHttpHelper(ChargeProperties chargeProperties, OkHttpClient client, ObjectMapper objectMapper) {
        super(chargeProperties, client, objectMapper);
    }

    @Override
    protected Object _post(Request.Builder requestBuilder, Type type, int count) throws IOException {
        okhttp3.Request request = requestBuilder.build();
        try{
            Response response = client.newCall(request).execute();
            if(response.code() != 200){
                throw new RequestFailureException(response);
            }
            ResponseBody responseBody = response.body();
            Result<String> strResult = objectMapper.readValue(responseBody.bytes(), new TypeReference<Result<String>>() {});
            Result<Object> objResult = new Result<>();
            objResult.setMsg(strResult.getMsg());
            objResult.setRet(strResult.getRet());
            objResult.setSig(strResult.getSig());
            if(!Strings.isNullOrEmpty(strResult.getData())){
                String data = strResult.getData();
                if(!data.startsWith("{") || data.startsWith("}")){
                    data = CryptoUtils.decodeByAes128_CBC_PKCS5Padding(data, config.getDataSecretIV(), config.getDataSecret());
                }
                objResult.setData(objectMapper.readValue(data, (Class<?>) ((ParameterizedTypeImpl) type).getActualTypeArguments()[0]));
            }
            return objResult;
        }catch (SocketTimeoutException e){
            if(count < config.getRetry()){
                log.error("POST " + request.url().url().getPath() + ": timeout and retry");
                return _post(requestBuilder, type, count + 1);
            }else {
                throw e;
            }
        }
    }
}
